package cn.iocoder.yudao.module.engine.service.billing;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.cache.NettyChannelCacheService;
import cn.iocoder.yudao.framework.cache.model.SessionContextCache;
import cn.iocoder.yudao.module.engine.constant.EngineConstant;
import cn.iocoder.yudao.module.engine.model.context.EngineSessionContext;
import cn.iocoder.yudao.module.infra.util.GameMatchIdUtil;
import cn.iocoder.yudao.module.infra.util.TraceIdUtil;
import cn.iocoder.yudao.module.resource.api.IUserTimeManagerApi;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.StopWatch;

import java.util.Collection;

@Slf4j
@Service
@RequiredArgsConstructor
public class BillingUserTimeScheduledTimer {
    private final IUserTimeManagerApi userTimeService;
    private final NettyChannelCacheService channelCacheService;

    @Scheduled(fixedDelay = 30_000)
    public void consumeTimeForOnlineUsers() {
        try {
            TraceIdUtil.setTraceId(IdUtil.objectId());
            log.info("计费用户时长-定时任务-开始");
            final StopWatch duration = new StopWatch();

            // 获取所有在线用户
            final Collection<SessionContextCache> onlineSessions = channelCacheService.getOnlineSessions();
            if (CollUtil.isEmpty(onlineSessions)) {
                log.info("计费用户时长-没有在线用户");
                return;
            }

            log.info("计费用户时长-在线用户数: {}", onlineSessions.size());

            onlineSessions.parallelStream().forEach(session -> {
                Long userId = null;
                String gameMatchId = null;
                try {
                    final EngineSessionContext sessionCtx = session.getSessionContext()
                            .getWithTimeout(EngineConstant.ENGINE_SESSION_KEY, 1000 * 10);
                    if (sessionCtx == null) {
                        log.warn("计费用户时长-sessionCtx为空, session = {}", session);
                        return;
                    }

                    TraceIdUtil.setTraceId(IdUtil.objectId());
                    GameMatchIdUtil.setMatchId(sessionCtx.getGameMatchId());

                    final String sessionId = sessionCtx.getWsSessionId();
                    if (!channelCacheService.isOnline(sessionId)) {
                        log.info("计费用户时长-用户已离线, userId = {}, sessionId = {}",
                                sessionCtx.getUserId(), sessionId);
                        return;
                    }

                    userId = sessionCtx.getUserId();
                    gameMatchId = sessionCtx.getGameMatchId();
                    final Integer roleId = sessionCtx.getRoleId();
                    final String roleName = sessionCtx.getRole().getName();

                    TraceIdUtil.setUserId(userId);

                    final boolean balanceSufficient = userTimeService.consumeTime(userId, gameMatchId, roleId, roleName, 10L);
                    sessionCtx.getBillingContext().setBalanceSufficient(balanceSufficient);
                    log.info("计费用户时长-余额是否充足, userId = {}, gameMatchId = {}, balanceSufficient = {}", userId, gameMatchId, balanceSufficient);
                } catch (Exception e) {
                    log.error(StrUtil.format("计费用户时长-异常, userId = {}, gameMatchId = {}", userId, gameMatchId), e);
                } finally {
                    TraceIdUtil.removeUserId();
                    GameMatchIdUtil.removeMatchId();
                    TraceIdUtil.removeTraceId();
                }
            });

            final long totalTimeMillis = duration.getTotalTimeMillis();
            log.info("计费用户时长-定时任务-结束, totalTimeMillis = {}", totalTimeMillis);
        } finally {
            TraceIdUtil.removeTraceId();
        }
    }
}